package app

import (
	"APT/internal/consts"
	"APT/internal/dao"
	"APT/internal/library/token"
	"APT/internal/model"
	"APT/internal/model/entity"
	"APT/internal/model/input/input_basics"
	"APT/internal/service"
	"APT/utility/encrypt"
	"context"
	"database/sql"
	"errors"
	"fmt"
	"github.com/gogf/gf/v2/container/gvar"
	"github.com/gogf/gf/v2/database/gdb"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/net/ghttp"
	"github.com/gogf/gf/v2/os/gtime"

	"github.com/gogf/gf/v2/errors/gerror"

	"APT/api/app/member"
)

func (c *ControllerMember) Login(ctx context.Context, req *member.LoginReq) (res *member.LoginRes, err error) {
	var (
		tx              gdb.TX
		orm             *gdb.Model
		ormWhereBuilder *gdb.WhereBuilder
		insertResult    sql.Result
		lastInsertId    int64
		MemberTokenInfo *model.MemberIdentity
		smsEvent        = "login"
		smsMobile       string
	)
	if tx, err = g.DB().Begin(ctx); err != nil {
		goto ERR
	}
	defer func() {
		if err != nil {
			_ = tx.Rollback()
		} else {
			_ = tx.Commit()
		}
	}()
	orm = dao.PmsMember.Ctx(ctx)
	ormWhereBuilder = orm.Builder()

	res = new(member.LoginRes)
	switch req.LoginType {
	case "email":
		if err = service.BasicsEmsLog().VerifyCode(ctx, &input_basics.VerifyEmsCodeInp{
			Event: smsEvent,
			Email: req.Email,
			Code:  req.Code,
		}); err != nil {
			return
		}
		orm = orm.Where(dao.PmsMember.Columns().Mail, req.Email)
		break
	case "phone":
		switch req.AreaNo {
		case "+81":
			smsEvent = "login-ja"
			smsMobile = fmt.Sprintf("%s%s", req.AreaNo, req.Phone)
			break
		case "+82":
			smsEvent = "login-ko"
			smsMobile = fmt.Sprintf("%s%s", req.AreaNo, req.Phone)
			break
		case "+86":
			smsEvent = "login"
			smsMobile = fmt.Sprintf("%s%s", req.AreaNo, req.Phone)
			break
		default:
			smsEvent = "login-en"
			smsMobile = fmt.Sprintf("%s%s", req.AreaNo, req.Phone)
			break
		}
		if err = service.BasicsSmsLog().VerifyCode(ctx, &input_basics.VerifyCodeInp{
			Event:  smsEvent,
			Mobile: smsMobile,
			Code:   req.Code,
		}); err != nil {
			return
		}
		orm = orm.Where(dao.PmsMember.Columns().Phone, req.Phone)
		orm = orm.Where(dao.PmsMember.Columns().PhoneArea, req.AreaNo)
		break
	case "password":
		ormWhereBuilder = ormWhereBuilder.WhereOr(dao.PmsMember.Columns().Mail, req.Email)
		ormWhereBuilder = ormWhereBuilder.WhereOr(g.MapStrAny{
			dao.PmsMember.Columns().Phone:     req.Phone,
			dao.PmsMember.Columns().PhoneArea: req.AreaNo,
		})
		orm = orm.Where(ormWhereBuilder)
		orm = orm.Where(dao.PmsMember.Columns().Password, encrypt.Md5([]byte(req.Password)))
		break
	case "yahooOauth":
	case "googleOauth":
		orm = orm.Where(dao.PmsMember.Columns().Mail, req.Email)
		break
	}
	if err = orm.OmitEmptyWhere().Scan(&MemberTokenInfo); err != nil && !errors.Is(err, sql.ErrNoRows) {
		goto ERR
	}
	if g.IsEmpty(MemberTokenInfo) && req.LoginType != "password" {
		// 查询是否已注销
		if err = dao.PmsMemberCancel.Ctx(ctx).
			Where(&entity.PmsMemberCancel{
				Phone:       req.Phone,
				PhoneArea:   req.AreaNo,
				Mail:        req.Email,
				AuditStatus: 2,
			}).OmitEmptyWhere().
			Scan(&MemberTokenInfo); err != nil && !errors.Is(err, sql.ErrNoRows) {
			goto ERR
		}
		if !g.IsEmpty(MemberTokenInfo) {
			// 获取会员注销设置
			var Config *input_basics.GetConfigModel
			Config, err = service.BasicsConfig().GetConfigByGroup(ctx, &input_basics.GetConfigInp{
				Group: "membercancelsetting",
			})
			if err != nil {
				err = gerror.Wrap(err, "未找到注销设置！")
				return
			}

			// 1-开启的话默认不能继续注册  2-关闭的话可以继续注册
			IsAllowedRegister := Config.List["isAllowedRegister"]
			if IsAllowedRegister == 1 {
				err = gerror.New("会员已注销！")
				return
			}
		}
		res.Replenish = true
		// 注册逻辑
		InsertData := &entity.PmsMember{}
		InsertData = &entity.PmsMember{
			Phone:           req.Phone,
			PhoneArea:       req.AreaNo,
			Mail:            req.Email,
			Source:          req.Source,
			LoginMode:       req.LoginType,
			LastLogin:       gtime.Now(),
			LastLoginIp:     ghttp.RequestFromCtx(ctx).GetClientIp(),
			RegisterIp:      ghttp.RequestFromCtx(ctx).GetClientIp(),
			RegisterTime:    gtime.Now(),
			RegisterMdCode:  req.MdCode,
			RegisterMpModel: req.MpModel,
			Referrer:        req.Referrer,
			LastReferrer:    req.Referrer,
		}

		if insertResult, err = orm.OmitEmptyData().Insert(InsertData); err != nil {
			goto ERR
		}
		if lastInsertId, err = insertResult.LastInsertId(); err != nil {
			goto ERR
		}
		if lastInsertId <= 0 {
			goto ERR
		}
		// 更新会员号
		MemberNo := fmt.Sprintf("888%05d", lastInsertId)
		if _, err = dao.PmsMember.Ctx(ctx).Where(dao.PmsMember.Columns().Id, lastInsertId).Update(g.MapStrAny{
			dao.PmsMember.Columns().MemberNo: MemberNo,
		}); err != nil {
			return
		}
		// 记录推荐记录
		if !g.IsEmpty(req.Referrer) {
			if _, err = dao.PmsReferrerLog.Ctx(ctx).Data(g.Slice{
				&entity.PmsReferrerLog{
					Referrer:     req.Referrer,
					MemberId:     gvar.New(lastInsertId).Int(),
					LastReferrer: req.Referrer,
				},
			}).InsertAndGetId(); err != nil {
				return
			}
		}

		MemberInfo := g.MapStrAny{
			dao.PmsMember.Columns().Id:       gvar.New(lastInsertId).Int(),
			dao.PmsMember.Columns().Phone:    req.Phone,
			dao.PmsMember.Columns().Mail:     req.Email,
			dao.PmsMember.Columns().Source:   req.Source,
			dao.PmsMember.Columns().MemberNo: MemberNo,
		}
		if err = gvar.New(MemberInfo).Struct(&MemberTokenInfo); err != nil {
			goto ERR
		}
		err = service.AppMember().RegisterMemberAward(ctx, tx, gvar.New(lastInsertId).Int())
	} else {

		// 获取会员信息
		var PmsMember entity.PmsMember
		if err = dao.PmsMember.Ctx(ctx).WherePri(MemberTokenInfo.Id).Scan(&PmsMember); err != nil {
			return
		}

		if g.IsEmpty(PmsMember) {
			err = gerror.New("会员信息不存在或已注销！")
			return
		}

		// 判断会员启用禁用状态
		if PmsMember.Status == 2 {
			err = gerror.New("会员已禁用！")
			return
		}

		PmsMemberInfoUpdate := g.MapStrAny{
			dao.PmsMember.Columns().LastLogin:   gtime.Now(),
			dao.PmsMember.Columns().LoginMode:   req.LoginType,
			dao.PmsMember.Columns().LastLoginIp: ghttp.RequestFromCtx(ctx).GetClientIp(),
		}

		if !g.IsEmpty(req.Referrer) {
			if g.IsEmpty(MemberTokenInfo.Referrer) {
				PmsMemberInfoUpdate[dao.PmsMember.Columns().Referrer] = req.Referrer
			}
			PmsMemberInfoUpdate[dao.PmsMember.Columns().LastReferrer] = req.Referrer

			// 插入记录
			if _, err = dao.PmsReferrerLog.Ctx(ctx).Data(g.MapStrAny{
				dao.PmsReferrerLog.Columns().MemberId:     MemberTokenInfo.Id,
				dao.PmsReferrerLog.Columns().LastReferrer: req.Referrer,
			}).InsertAndGetId(); err != nil {
				return
			}
		}
		// 更新登录时间和IP
		if _, err = dao.PmsMember.Ctx(ctx).Where(dao.PmsMember.Columns().Id, MemberTokenInfo.Id).Update(PmsMemberInfoUpdate); err != nil {
			goto ERR
		}
		res.Replenish = MemberTokenInfo.Replenish == "N"
	}
	MemberTokenInfo.LoginAt = gtime.Now()
	MemberTokenInfo.App = consts.AppMember
	if res.Token, res.Expires, err = token.MemberLogin(ctx, MemberTokenInfo); err != nil {
		goto ERR
	}
	// 记录登录记录
	if _, err = dao.PmsMemberLog.Ctx(ctx).Data(&entity.PmsMemberLog{
		MemberId:  MemberTokenInfo.Id,
		LoginTime: gtime.Now(),
		LoginType: req.LoginType,
		LoginIp:   ghttp.RequestFromCtx(ctx).GetClientIp(),
		Token:     res.Token,
		ExpirTime: gtime.New(res.Expires + gtime.Now().Unix()),
		MdCode:    req.MdCode,
		MpModel:   req.MpModel,
	}).Insert(); err != nil {
		return
	}
	return
ERR:
	g.Log().Error(ctx, err)
	err = errors.New("loginFail")
	return
}
func (c *ControllerMember) AuthIdBindLogin(ctx context.Context, req *member.AuthIdBindLoginReq) (res *member.AuthIdBindLoginRes, err error) {
	var (
		PmsMemberAuth   *entity.PmsMemberAuth
		PmsMember       *entity.PmsMember
		insertResult    sql.Result
		lastInsertId    int64
		MemberTokenInfo *model.MemberIdentity
		tx              gdb.TX
		MemberInfo      g.MapStrAny
		MobileNo        string
		smsEvent        string
	)
	if tx, err = g.DB().Begin(ctx); err != nil {
		return
	}
	defer func() {
		if err != nil {
			_ = tx.Rollback()
		} else {
			_ = tx.Commit()
		}
	}()
	res = new(member.AuthIdBindLoginRes)
	// 查询是否存在该AuthId
	if err = dao.PmsMemberAuth.Ctx(ctx).Where(dao.PmsMemberAuth.Columns().AuthId, req.AuthId).Scan(&PmsMemberAuth); err != nil {
		return
	}
	if g.IsEmpty(PmsMemberAuth) {
		err = gerror.New("绑定失败")
		return
	}
	if !g.IsEmpty(PmsMemberAuth.MemberId) {
		err = gerror.New("该账号已被绑定")
		return
	}
	switch req.BindType {
	case "PHONE", "phone":
		switch req.AreaNo {
		case "+81":
			smsEvent = "login-ja"
			MobileNo = fmt.Sprintf("%s%s", req.AreaNo, req.Phone)
			break
		case "+82":
			smsEvent = "login-ko"
			MobileNo = fmt.Sprintf("%s%s", req.AreaNo, req.Phone)
			break
		case "+86":
			smsEvent = "login"
			MobileNo = fmt.Sprintf("%s%s", req.AreaNo, req.Phone)
			break
		default:
			smsEvent = "login-en"
			MobileNo = fmt.Sprintf("%s%s", req.AreaNo, req.Phone)
			break
		}
		if err = service.BasicsSmsLog().VerifyCode(ctx, &input_basics.VerifyCodeInp{
			Event:  smsEvent,
			Mobile: MobileNo,
			Code:   req.Code,
		}); err != nil {
			return
		}
		break
	case "EMAIL", "email":
		if err = service.BasicsEmsLog().VerifyCode(ctx, &input_basics.VerifyEmsCodeInp{
			Event: "login",
			Email: req.Email,
			Code:  req.Code,
		}); err != nil {
			return
		}
		break
	}
	// 查询是否存在用户信息
	if !g.IsEmpty(req.Email) {
		req.AreaNo = ""
	}
	if err = dao.PmsMember.Ctx(ctx).OmitEmptyWhere().Where(g.MapStrAny{
		dao.PmsMember.Columns().Phone:     req.Phone,
		dao.PmsMember.Columns().PhoneArea: req.AreaNo,
		dao.PmsMember.Columns().Mail:      req.Email,
	}).Scan(&PmsMember); err != nil {
		return
	}
	if g.IsEmpty(PmsMember) {
		// 查询是否已注销
		if err = dao.PmsMemberCancel.Ctx(ctx).
			Where(&entity.PmsMemberCancel{
				Phone:       req.Phone,
				PhoneArea:   req.AreaNo,
				Mail:        req.Email,
				AuditStatus: 2,
			}).OmitEmptyWhere().
			Scan(&MemberTokenInfo); err != nil && !errors.Is(err, sql.ErrNoRows) {
			g.Log().Error(ctx, err)
			err = gerror.New("登录失败")
			return
		}
		if !g.IsEmpty(MemberTokenInfo) {
			// 获取会员注销设置
			var Config *input_basics.GetConfigModel
			Config, err = service.BasicsConfig().GetConfigByGroup(ctx, &input_basics.GetConfigInp{
				Group: "membercancelsetting",
			})
			if err != nil {
				err = gerror.Wrap(err, "未找到注销设置！")
				return
			}

			IsAllowedRegister := Config.List["isAllowedRegister"]
			if IsAllowedRegister == 1 {
				err = gerror.New("会员已注销！")
				return
			}
		}
		// 注册逻辑
		InsertData := &entity.PmsMember{
			Phone:           req.Phone,
			PhoneArea:       req.AreaNo,
			Mail:            req.Email,
			Source:          req.Source,
			LoginMode:       PmsMemberAuth.Channel,
			LastLogin:       gtime.Now(),
			LastLoginIp:     ghttp.RequestFromCtx(ctx).GetClientIp(),
			RegisterIp:      ghttp.RequestFromCtx(ctx).GetClientIp(),
			RegisterTime:    gtime.Now(),
			RegisterMdCode:  req.MdCode,
			RegisterMpModel: req.MpModel,
			Referrer:        req.Referrer,
			LastReferrer:    req.Referrer,
		}
		if insertResult, err = dao.PmsMember.Ctx(ctx).TX(tx).OmitEmptyData().Insert(InsertData); err != nil {
			return
		}
		if lastInsertId, err = insertResult.LastInsertId(); err != nil {
			return
		}
		if lastInsertId <= 0 {
			err = gerror.New("绑定失败")
			return
		}
		// 更新会员号
		MemberNo := fmt.Sprintf("888%05d", lastInsertId)
		if _, err = dao.PmsMember.Ctx(ctx).TX(tx).Where(dao.PmsMember.Columns().Id, lastInsertId).Update(g.MapStrAny{
			dao.PmsMember.Columns().MemberNo: MemberNo,
		}); err != nil {
			return
		}
		MemberInfo = g.MapStrAny{
			dao.PmsMember.Columns().Id:       gvar.New(lastInsertId).Int(),
			dao.PmsMember.Columns().Phone:    req.Phone,
			dao.PmsMember.Columns().Mail:     req.Email,
			dao.PmsMember.Columns().Source:   req.Source,
			dao.PmsMember.Columns().MemberNo: MemberNo,
		}
		res.Replenish = true
		err = service.AppMember().RegisterMemberAward(ctx, tx, gvar.New(lastInsertId).Int())
	} else {
		if _, err = dao.PmsMemberAuth.Ctx(ctx).Where(dao.PmsMemberAuth.Columns().AuthId, req.AuthId).Data(g.MapStrAny{
			dao.PmsMemberAuth.Columns().MemberId: PmsMember.Id,
		}).Update(); err != nil {
			return
		}
		MemberInfo = g.MapStrAny{
			dao.PmsMember.Columns().Id:       PmsMember.Id,
			dao.PmsMember.Columns().Phone:    req.Phone,
			dao.PmsMember.Columns().Mail:     req.Email,
			dao.PmsMember.Columns().Source:   req.Source,
			dao.PmsMember.Columns().MemberNo: PmsMember.MemberNo,
		}
		res.Replenish = PmsMember.Replenish == "N"
	}

	if err = gvar.New(MemberInfo).Struct(&MemberTokenInfo); err != nil {
		return
	}
	if res.Token, res.Expires, err = token.MemberLogin(ctx, MemberTokenInfo); err != nil {
		return
	}
	if _, err = dao.PmsMemberAuth.Ctx(ctx).TX(tx).Where(g.MapStrAny{
		dao.PmsMemberAuth.Columns().AuthId: req.AuthId,
	}).Update(g.MapStrAny{
		dao.PmsMemberAuth.Columns().MemberId: MemberTokenInfo.Id,
	}); err != nil {
		return
	}
	// 记录登录记录
	if _, err = dao.PmsMemberLog.Ctx(ctx).TX(tx).Data(&entity.PmsMemberLog{
		MemberId:  MemberTokenInfo.Id,
		LoginTime: gtime.Now(),
		LoginType: PmsMemberAuth.Channel,
		LoginIp:   ghttp.RequestFromCtx(ctx).GetClientIp(),
		Token:     res.Token,
		ExpirTime: gtime.New(res.Expires + gtime.Now().Unix()),
		MdCode:    req.MdCode,
		MpModel:   req.MpModel,
	}).Insert(); err != nil {
		return
	}

	return
}
